package com.obrock;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.exception.*;
import com.dropbox.client2.session.AccessTokenPair;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.Session;

import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Created with IntelliJ IDEA.
 * User: Rick
 * Date: 07.10.12
 * Time: 21:10
 * To change this template use File | Settings | File Templates.
 */
public class Dropbox {
    final static private String APP_KEY = "3wzm6sdosmafo73";
    final static private String APP_SECRET = "jbz5qwlgv6yaaaz";
    final static private Session.AccessType ACCESS_TYPE = Session.AccessType.APP_FOLDER;
    final static private String FILE_PATH = "/backup";

    final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
    final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";

    //static private int SYNC_PERIOD = 600000;

    private DropboxAPI<AndroidAuthSession> api;
    public String mErrorMsg = "";
    public long lastRevision = 0;
    public boolean mLoggedIn;
    private Context context;


    public Dropbox(Context context) {
        this.context = context;
    }

    public AndroidAuthSession login(Context context) {
        AndroidAuthSession session;
        String[] stored = getKeys();
        if (stored == null) {
            AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
            session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
            api = new DropboxAPI<AndroidAuthSession>(session);
            api.getSession().startAuthentication(context);
        } else {
            session = new AndroidAuthSession(
                    new AppKeyPair(APP_KEY, APP_SECRET),
                    ACCESS_TYPE,
                    new AccessTokenPair(stored[0], stored[1]));
            api = new DropboxAPI<AndroidAuthSession>(session);
        }

        mLoggedIn = api.getSession().isLinked();
        if (mLoggedIn) {
            synchronized (DropboxThread.loginObject) {
                DropboxThread.loginObject.notify();
            }
        }
        return session;
    }

    public void logOut() {
        // Remove credentials from the session
        if (api != null && api.getSession() != null) {
            api.getSession().unlink();
        }
        mLoggedIn = false;
    }

    public void drop() {
        SharedPreferences prefs = context.getSharedPreferences(Main.PREFERENCES_NAME, 0);
        SharedPreferences.Editor edit = prefs.edit();
        edit.remove(ACCESS_KEY_NAME);
        edit.remove(ACCESS_SECRET_NAME);
        edit.commit();
        if (mLoggedIn) {
            logOut();
        }
    }

    /*
    private boolean needBackup() {
        SharedPreferences prefs = context.getSharedPreferences(Main.PREFERENCES_NAME, 0);
        long now = new Date().getTime() / 3600000;
        if (prefs.getLong("LAST_BACKUP", 0) != now) {
            SharedPreferences.Editor edit = prefs.edit();
            edit.putLong("LAST_BACKUP", now);
            edit.commit();
            return true;
        } else {
            return false;
        }

    }
    */

    public void checkLogin() {
        if (api != null) {
            AndroidAuthSession session = api.getSession();
            if (session != null && session.authenticationSuccessful()) {
                try {
                    session.finishAuthentication();

                    AccessTokenPair tokens = session.getAccessTokenPair();
                    storeKeys(tokens.key, tokens.secret);

                    mLoggedIn = true;
                    synchronized (DropboxThread.loginObject) {
                        DropboxThread.loginObject.notify();
                    }

                    //force();

                } catch (IllegalStateException e) {
                    Log.e(Main.LOG_TAG, e.getMessage());
                    //Main.toast("Couldn't authenticate with Dropbox:" + e.getLocalizedMessage());
                }
            }
        }
    }

    public boolean upload(byte[] data) {

        if (api == null) return false;

        ByteArrayInputStream baStream = new ByteArrayInputStream(data);
        DataInputStream in = new DataInputStream(baStream);

        try {
            try {
                DropboxAPI.Entry info = api.metadata(FILE_PATH, 1, null, false, null);

                Calendar remoteTime = Calendar.getInstance(TimeZone.getDefault());
                Date d = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US).parse(info.modified.toString());
                remoteTime.setTime(d);

                Calendar localTime = Calendar.getInstance(TimeZone.getDefault());

                if (remoteTime.get(Calendar.DAY_OF_MONTH) != localTime.get(Calendar.DAY_OF_MONTH)) {

                    Calendar x = (Calendar) localTime.clone();
                    x.add(Calendar.DAY_OF_MONTH, -10);
                    localTime.add(Calendar.DAY_OF_MONTH, -1);

                    String del = FILE_PATH + String.format("-%04d-%02d-%02d",
                            x.get(Calendar.YEAR),
                            x.get(Calendar.MONTH),
                            x.get(Calendar.DAY_OF_MONTH));

                    String ndy = FILE_PATH + String.format("-%04d-%02d-%02d",
                            localTime.get(Calendar.YEAR),
                            localTime.get(Calendar.MONTH),
                            localTime.get(Calendar.DAY_OF_MONTH));
                    try {
                        api.delete(del);
                    } catch (Exception ex) {
                    }

                    /*
                    for (int i = 9; i >= 0; --i) {
                        String from = FILE_PATH + String.format("-%02d", i - 1);
                        String to = FILE_PATH + String.format("-%02d", i);
                        try {
                            api.move(from, to);
                        } catch (Exception ex) {
                        }


                    String from = FILE_PATH;
                    String to = FILE_PATH + "-00";
                    */

                    api.move(FILE_PATH, ndy);
                }
            } catch (Exception ex) {
            }

            DropboxAPI.Entry info = api.putFileOverwrite(FILE_PATH, in, data.length, null);
            lastRevision = Long.parseLong(info.rev, 16);
            return true;

        } catch (DropboxUnlinkedException e) {
            // This session wasn't authenticated properly or user unlinked
            mErrorMsg = "This app wasn't authenticated properly.";
        } catch (DropboxFileSizeException e) {
            // File size too big to upload via the API
            mErrorMsg = "This file is too big to upload";
        } catch (DropboxPartialFileException e) {
            // We canceled the operation
            mErrorMsg = "Upload canceled";
        } catch (DropboxServerException e) {
            // Server-side exception.  These are examples of what could happen,
            // but we don't do anything special with them here.
            if (e.error == DropboxServerException._401_UNAUTHORIZED) {
                // Unauthorized, so we should unlink them.  You may want to
                // automatically log the user out in this case.
            } else if (e.error == DropboxServerException._403_FORBIDDEN) {
                // Not allowed to access this
            } else if (e.error == DropboxServerException._404_NOT_FOUND) {
                // path not found (or if it was the thumbnail, can't be
                // thumbnailed)
            } else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
                // user is over quota
            } else {
                // Something else
            }
            // This gets the Dropbox error, translated into the user's language
            mErrorMsg = e.body.userError;
            if (mErrorMsg == null) {
                mErrorMsg = e.body.error;
            }
        } catch (DropboxIOException e) {
            // Happens all the time, probably want to retry automatically.
            mErrorMsg = "Network error.  Try again.";
        } catch (DropboxParseException e) {
            // Probably due to Dropbox server restarting, should retry
            mErrorMsg = "Dropbox error.  Try again.";
        } catch (DropboxException e) {
            // Unknown error
            mErrorMsg = "Unknown error.  Try again.";
            /*} catch (ParseException e) {
            mErrorMsg = "Data parse error";
            */
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
        if (mErrorMsg.length() > 0) {
            Log.e(Main.LOG_TAG, mErrorMsg);
        }

        //Main.toast(mErrorMsg);
        return false;
        //}
    }

    public long revision() {
        long rev = 0;
        try {
            DropboxAPI.Entry info = api.metadata(FILE_PATH, 1, null, false, null);
            rev = Long.parseLong(info.rev, 16);
        } catch (DropboxException e) {
            rev = -1;
            mErrorMsg = "Something went wrong while getting metadata.";
        }
        return rev;
    }

    public byte[] download() {

        if (api == null) return null;

        ByteArrayOutputStream data = new ByteArrayOutputStream();
        DataOutputStream out = new DataOutputStream(data);

        try {
            DropboxAPI.DropboxFileInfo info = api.getFile(FILE_PATH, null, out, null);
            lastRevision = Long.parseLong(info.getMetadata().rev, 16);
            return data.toByteArray();
        } catch (DropboxUnlinkedException e) {
            // The AuthSession wasn't properly authenticated or user unlinked.
        } catch (DropboxPartialFileException e) {
            // We canceled the operation
            mErrorMsg = "Download canceled";
        } catch (DropboxServerException e) {
            // Server-side exception.  These are examples of what could happen,
            // but we don't do anything special with them here.
            if (e.error == DropboxServerException._304_NOT_MODIFIED) {
                // won't happen since we don't pass in revision with metadata
            } else if (e.error == DropboxServerException._401_UNAUTHORIZED) {
                // Unauthorized, so we should unlink them.  You may want to
                // automatically log the user out in this case.
            } else if (e.error == DropboxServerException._403_FORBIDDEN) {
                // Not allowed to access this
            } else if (e.error == DropboxServerException._404_NOT_FOUND) {
                // path not found (or if it was the thumbnail, can't be
                // thumbnailed)
            } else if (e.error == DropboxServerException._406_NOT_ACCEPTABLE) {
                // too many entries to return
            } else if (e.error == DropboxServerException._415_UNSUPPORTED_MEDIA) {
                // can't be thumbnailed
            } else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
                // user is over quota
            } else {
                // Something else
            }
            // This gets the Dropbox error, translated into the user's language
            mErrorMsg = e.body.userError;
            if (mErrorMsg == null) {
                mErrorMsg = e.body.error;
            }
        } catch (DropboxIOException e) {
            // Happens all the time, probably want to retry automatically.
            mErrorMsg = "Network error.  Try again.";
        } catch (DropboxParseException e) {
            // Probably due to Dropbox server restarting, should retry
            mErrorMsg = "Dropbox error.  Try again.";
        } catch (DropboxException e) {
            // Unknown error
            mErrorMsg = "Unknown error.  Try again.";
        }
        //Main.toast(mErrorMsg);
        Log.e(Main.LOG_TAG, mErrorMsg);
        return null;
    }

    private void storeKeys(String key, String secret) {
        // Save the access key for later
        SharedPreferences prefs = context.getSharedPreferences(Main.PREFERENCES_NAME, 0);
        SharedPreferences.Editor edit = prefs.edit();
        edit.putString(ACCESS_KEY_NAME, key);
        edit.putString(ACCESS_SECRET_NAME, secret);
        edit.commit();
    }

    private String[] getKeys() {
        SharedPreferences prefs = context.getSharedPreferences(Main.PREFERENCES_NAME, 0);
        String key = prefs.getString(ACCESS_KEY_NAME, null);
        String secret = prefs.getString(ACCESS_SECRET_NAME, null);
        if (key != null && secret != null) {
            String[] ret = new String[2];
            ret[0] = key;
            ret[1] = secret;
            return ret;
        } else {
            return null;
        }
    }


}
